package SeqFunc

import (
	//"fmt"

	"git.oschina.net/yangdao/SGLisp"
	. "git.oschina.net/yangdao/SGLisp/parse"
	. "git.oschina.net/yangdao/extlib"
	. "git.oschina.net/yangdao/extlib/data_type"
)

type SeqFunc struct {
	seqFuncNodes *TypVector
	FuncContext  *SGLisp.Context
	IsRun        bool

	isBlockNode bool
	curNodeIdx  int
}

func NewSeqFunc(context *SGLisp.Context) *SeqFunc {
	return &SeqFunc{
		seqFuncNodes: Vector(),
		FuncContext:  SGLisp.NewContext(context),
	}
}

func (this *SeqFunc) AddSeqFunc(seqFunc ISeqFuncNode) {
	this.seqFuncNodes.Conj(seqFunc)
}

func (this *SeqFunc) Run() {
	this.IsRun = true
}

func (this *SeqFunc) Update(dt float64) {
	if this.IsRun == false || this.seqFuncNodes.Count() == 0 {
		return
	}

	funcNode := this.seqFuncNodes.Nth(this.curNodeIdx).(ISeqFuncNode)
	for this.curNodeIdx < this.seqFuncNodes.Count() && !this.isBlockNode {

		if funcNode.Info().SeqFuncType == SeqFuncNodeType_NonBlock {
			this.curNodeIdx++
			funcNode.OnCall(this.FuncContext)
			this.isBlockNode = false
			if this.curNodeIdx >= this.seqFuncNodes.Count() {
				this.IsRun = false
				return
			}
			funcNode = this.seqFuncNodes.Nth(this.curNodeIdx).(ISeqFuncNode)
		} else {
			this.isBlockNode = true
			funcNode.(IBlockSeqFuncNode).OnCall(this.FuncContext)
		}
	}

	if this.isBlockNode && funcNode != nil {
		blockFunNode := funcNode.(IBlockSeqFuncNode)
		blockFunNode.Update(dt)
		if blockFunNode.Info().IsFinish {
			this.isBlockNode = false
			this.curNodeIdx++
		}
		if this.curNodeIdx == this.seqFuncNodes.Count() {
			this.IsRun = false
		}
	}
}

func (this *SeqFunc) Clone() *SeqFunc {
	cloneSeqFunc := NewSeqFunc(this.FuncContext.Parent())
	cloneSeqFunc.IsRun = false
	for symName, _ := range this.FuncContext.GetSymblos() {
		cloneSeqFunc.FuncContext.Define(symName, SGLisp.StaticNilNode)
	}
	ForEach(this.seqFuncNodes, func(v interface{}) {
		seqFunc := v.(ISeqFuncNode)
		switch seqFunc.Info().SeqFuncType {
		case SeqFuncNodeType_Block:
			createFn := this.FuncContext.LookUp(v.(ISeqFuncNode).Info().Name).(*ObjectNode).Val.(func() IBlockSeqFuncNode)
			newBlockFn := createFn()
			newBlockFn.Info().Name = seqFunc.Info().Name
			newBlockFn.Info().LispNode = seqFunc.Info().LispNode
			newBlockFn.OnLoad(newBlockFn.Info().LispNode.Children())
			cloneSeqFunc.AddSeqFunc(newBlockFn)
		case SeqFuncNodeType_NonBlock:
			nonblockNode := seqFunc.(*NonBlockSeqFuncNode)
			cloneSeqFunc.AddSeqFunc(nonblockNode)
		}
	})

	return cloneSeqFunc
}
